package com.mgy.example.service.common.lock.aop;

import com.mgy.example.annotation.RedisLock;
import com.mgy.example.utils.LockUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Aspect
@Component
public class RedisLockAspect {

    @Autowired
    private Redisson redissonClient;

    @Pointcut("@annotation(com.mgy.example.annotation.RedisLock)")
    public void distributedLockPointcut() {

    }

    @Around(value = "distributedLockPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        RedisLock redisLock = methodSignature.getMethod().getAnnotation(RedisLock.class);
        String[] parameterNames = methodSignature.getParameterNames();
        Class[] parameterTypes = methodSignature.getMethod().getParameterTypes();
        Object[] parameterValues = joinPoint.getArgs();
        //获取锁的名称
        String lockName = LockUtil.getLockName(redisLock.lockName(), redisLock.fieldName(), parameterNames, parameterTypes, parameterValues);
        long waitTime = redisLock.waitTime();
        long timeout = redisLock.timeout();

        RLock rLock = redissonClient.getLock(lockName);
        try {
            //加锁
            if (waitTime > 0 && timeout > 0) {
                rLock.tryLock(waitTime, timeout, TimeUnit.SECONDS);
            } else if (timeout > 0) {
                rLock.tryLock(timeout, TimeUnit.SECONDS);
            } else {
                rLock.lock();
            }
            //执行业务方法
            return joinPoint.proceed();
        } finally {
            //解锁
            if (rLock != null) {
                rLock.unlock();
            }
        }
    }


}
